#include "CGame.h"

CGame* CGame::_instance=NULL;

CGame* CGame::GetInstance()
{
	if(_instance==NULL)
	{
		_instance=new CGame();
	}
	return _instance;
}

CGame::CGame()
{
	_d3d = NULL;
	_d3ddv = NULL;
	_backBuffer = NULL;

	_di = NULL;
	_keyboard = NULL;

	_mode = MODE;
	_SetScreenDimension(_mode);
	_name = PROJECT_NAME;
	_isFullScreen = IS_FULLSCREEN;
	_frameRate = FRAME_RATE;
}

void CGame::_SetScreenDimension(int Mode)
{
	switch (Mode)
	{
	case GL_GAME_SCREEN_RESOLUTION_640_480_24:
		_screenWidth = 640; 
		_screenHeight = 480;
		_depth = 24;
		_backBufferFormat = D3DFMT_X8R8G8B8;
		break;

	case GL_GAME_SCREEN_RESOLUTION_800_600_24:
		_screenWidth = 800; 
		_screenHeight = 600;
		_depth = 24;
		_backBufferFormat = D3DFMT_X8R8G8B8;
		break;

	case GL_GAME_SCREEN_RESOLUTION_1024_768_24:
		_screenWidth = 1024; 
		_screenHeight = 768;
		_depth = 24;
		_backBufferFormat = D3DFMT_X8R8G8B8;
		break;

	default: 
		break;
	}
}

bool CGame::_InitWindow(HINSTANCE hInstance)
{
	_hInstance=hInstance;

	WNDCLASSEX wc;
	wc.cbSize = sizeof(WNDCLASSEX);

	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.hInstance = _hInstance;

	wc.lpfnWndProc = (WNDPROC)CGame::_WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = _name;
	wc.hIconSm = NULL;
	
	if(!RegisterClassEx(&wc))
	{
		return false;
	}

	DWORD style; 
	if (_isFullScreen)
		style = WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP;
	else 
		style = WS_OVERLAPPEDWINDOW;

	_hWnd = 
		CreateWindow(
			_name,
			_name,
			style, 
			CW_USEDEFAULT,
			CW_USEDEFAULT, 
			_screenWidth,
			_screenHeight,
			NULL,
			NULL,
			_hInstance,
			NULL);
	
	if (!_hWnd) 
	{ 
		trace(L"[ERROR] Failed to created window!");
		DWORD ErrCode = GetLastError();

		return false;
	}

	ShowWindow(_hWnd,SW_SHOWNORMAL);
	UpdateWindow(_hWnd);
	return true;
}

bool CGame::_InitDirectX()
{
	_d3d = Direct3DCreate9(D3D_SDK_VERSION);

	if(!_d3d)
	{
		return false;
	}

	D3DPRESENT_PARAMETERS d3dpp; 

	ZeroMemory( &d3dpp, sizeof(d3dpp) );

	d3dpp.Windowed = _isFullScreen?FALSE:TRUE;

	d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

	d3dpp.BackBufferFormat = _backBufferFormat; 
	d3dpp.BackBufferCount = 1;
	d3dpp.BackBufferHeight = _screenHeight;
	d3dpp.BackBufferWidth = _screenWidth;

	_d3d->CreateDevice(
			D3DADAPTER_DEFAULT,
			D3DDEVTYPE_HAL,
			_hWnd,
			D3DCREATE_SOFTWARE_VERTEXPROCESSING,
			&d3dpp,
			&_d3ddv);

	if (_d3ddv==NULL) 
	{
		trace(L"[ERROR] Failed to created device!");
		return false;
	}
	
	_d3ddv->GetBackBuffer(0,0,D3DBACKBUFFER_TYPE_MONO,&_backBuffer);
	D3DXCreateSprite(_d3ddv, &_spriteHandler);

	if(!_InitDirectSound())
	{
		return false;
	}

	return true;
}

void CGame::_InitKeyboard()
{
	_input = new Input(_hWnd);
}

bool CGame::Init(HINSTANCE hInstance)
{
	if(!_InitWindow(hInstance))
	{
		return false;
	}

	if(!_InitDirectX())
	{
		return false;
	}

	_InitKeyboard();

	/*_LoadResource*/
	ResourceManager::GetInstance();
	
	SceneManager::GetInstance()->PushScene((Scene*) new MenuScene());	

	return true;
}

void CGame::_ProcessKeyBoard()
{

	_input->_ReadKeyBoard();
	_input->_Process_KeyBoard();

	//Thoat
	if (_input->IsKeyDown(DIK_ESCAPE)) 
	{
		trace(L"Escape key pressed!");
		PostMessage(_hWnd,WM_QUIT,0,0);
	}
	
}

void CGame::Run()
{
	MSG msg;
	int done = 0;
	DWORD frame_start = GetTickCount();
	
	_tickperframe = (float)1000 / _frameRate;
	
	trace(L">>> Main game loop has been started");

	while (!done) 
	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if (msg.message==WM_QUIT) done=1;

			TranslateMessage(&msg);
			DispatchMessage(&msg);			
		}

		_ProcessKeyBoard();

		DWORD now = GetTickCount();
		_deltaTime = now - frame_start; 
		if (_deltaTime >= _tickperframe)
		{
			frame_start = now;
			_Update((float)_deltaTime);
			_Render();
		}

		

		

		/*_ProcessInput(_d3ddv, _DeltaTime);*/ //xet di chuyen Mario trong Scene
	}

	trace(L"Main game loop has ended");
}

void CGame::_Update(float Delta)
{
	// Update logic
	SceneManager::GetInstance()->Update(Delta);
}

void CGame::_Render()
{
	_StartRender();
	_Start2DRender();

	// Draw
	SceneManager::GetInstance()->Render();

	_Stop2DRender();
	_StopRender();
}

CGame::~CGame()
{
	if (_d3ddv!=NULL) _d3ddv->Release();
	if (_d3d!=NULL) _d3d->Release();

    if( _keyboard )  
	{
		_keyboard->Unacquire();
		_keyboard->Release();
	}

    if (_di) _di->Release();
}

LRESULT CALLBACK CGame::_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	switch (message) 
	{
		case WM_DESTROY: 
			PostQuitMessage(0);
			break;
		default: 
			return DefWindowProc(hWnd, message, wParam,lParam);
	}

	return 0;
}

void CGame::Release()
{
	if (_d3ddv!=NULL) _d3ddv->Release();
	if (_d3d!=NULL) _d3d->Release();

    if( _keyboard )  
	{
		_keyboard->Unacquire();
		_keyboard->Release();
	}

    if (_di) _di->Release();
}

void CGame::_Start2DRender()
{
	_spriteHandler->Begin(D3DXSPRITE_ALPHABLEND);
}

void CGame::_Stop2DRender()
{
	_spriteHandler->End();
}

void CGame::_StartRender()
{
	_d3ddv->BeginScene();
}

void CGame::_StopRender()
{
	_d3ddv->EndScene();
	//display the back buffer on the screen
	_d3ddv->Present(NULL,NULL,NULL,NULL);
}

int CGame::GetScreenHeight()
{
	return _screenHeight;
}

int CGame::GetScreenWidth()
{
	return _screenWidth;
}

int CGame::GetDepth()
{
	return _depth;
}

float CGame::GetFPS()
{
	///
	return 0;
}

HWND CGame::GetWindowHandle()
{
	return _hWnd;
}

LPDIRECT3DDEVICE9 CGame::GetD3DDevice()
{
	return _d3ddv;
}

LPD3DXSPRITE CGame::GetSpriteHandle()
{
	return _spriteHandler;
}

LPDIRECT3DSURFACE9 CGame::GetBackBuffer()
{
	return _backBuffer;
}

Input* CGame::GetInput()
{
	return _input;
}

bool CGame::_InitDirectSound()
{
	HRESULT hr;
	DSBUFFERDESC bufferDesc;
	WAVEFORMATEX waveFormat;


	hr=DirectSoundCreate8( NULL, &_dSound, NULL );

	if(FAILED(hr))
	{
		return false;
	}

	hr = _dSound->SetCooperativeLevel( _hWnd, DSSCL_PRIORITY );

	if(FAILED(hr))
	{
		return false;
	}

	// Setup the primary buffer description.
	bufferDesc.dwSize = sizeof(DSBUFFERDESC);
	bufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_CTRLVOLUME;
	bufferDesc.dwBufferBytes = 0;
	bufferDesc.dwReserved = 0;
	bufferDesc.lpwfxFormat = NULL;
	bufferDesc.guid3DAlgorithm = GUID_NULL;
 
	// Get control of the primary sound buffer on the default sound device.
	hr = _dSound->CreateSoundBuffer(&bufferDesc, &_primaryBuffer, NULL);
	if(FAILED(hr))
	{
		return false;
	}

	// Setup the format of the primary sound bufffer.
	// In this case it is a .WAV file recorded at 44,100 samples per second in 16-bit stereo (cd audio format).
	waveFormat.wFormatTag = WAVE_FORMAT_PCM;
	waveFormat.nSamplesPerSec = 16000;
	waveFormat.wBitsPerSample = 16;
	waveFormat.nChannels = 1;
	waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
	waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
	waveFormat.cbSize = 0;
 
	// Set the primary buffer to be the wave format specified.
	hr = _primaryBuffer->SetFormat(&waveFormat);
	if(FAILED(hr))
	{
		return false;
	}
 
	return true;

}

void CGame::_ReleaseDirectSound()
{
	// Release the primary sound buffer pointer.
	if(_primaryBuffer)
	{
		_primaryBuffer->Release();
		_primaryBuffer = 0;
	}
 
	// Release the direct sound interface pointer.
	if(_dSound)
	{
		_dSound->Release();
		_dSound = 0;
	}
 
	return;
}